

<!DOCTYPE html>
<!--[if IE 8]><html class="no-js lt-ie9" lang="en" > <![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js" lang="en" > <!--<![endif]-->
<head>
  <meta charset="utf-8">
  
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta name="Description" content="scikit-learn: machine learning in Python">

  
  <title>How to optimize for speed &mdash; scikit-learn 0.22 documentation</title>
  
  <link rel="canonical" href="http://scikit-learn.org/stable/developers/performance.html" />

  
  <link rel="shortcut icon" href="../_static/favicon.ico"/>
  

  <link rel="stylesheet" href="../_static/css/vendor/bootstrap.min.css" type="text/css" />
  <link rel="stylesheet" href="../_static/gallery.css" type="text/css" />
  <link rel="stylesheet" href="../_static/css/theme.css" type="text/css" />
<script id="documentation_options" data-url_root="../" src="../_static/documentation_options.js"></script>
<script src="../_static/jquery.js"></script> 
</head>
<body>
<nav id="navbar" class="sk-docs-navbar navbar navbar-expand-md navbar-light bg-light py-0">
  <div class="container-fluid sk-docs-container px-0">
      <a class="navbar-brand py-0" href="../index.html">
        <img
          class="sk-brand-img"
          src="../_static/scikit-learn-logo-small.png"
          alt="logo"/>
      </a>
    <button
      id="sk-navbar-toggler"
      class="navbar-toggler"
      type="button"
      data-toggle="collapse"
      data-target="#navbarSupportedContent"
      aria-controls="navbarSupportedContent"
      aria-expanded="false"
      aria-label="Toggle navigation"
    >
      <span class="navbar-toggler-icon"></span>
    </button>

    <div class="sk-navbar-collapse collapse navbar-collapse" id="navbarSupportedContent">
      <ul class="navbar-nav mr-auto">
        <li class="nav-item">
          <a class="sk-nav-link nav-link" href="../install.html">Install</a>
        </li>
        <li class="nav-item">
          <a class="sk-nav-link nav-link" href="../user_guide.html">User Guide</a>
        </li>
        <li class="nav-item">
          <a class="sk-nav-link nav-link" href="../modules/classes.html">API</a>
        </li>
        <li class="nav-item">
          <a class="sk-nav-link nav-link" href="../auto_examples/index.html">Examples</a>
        </li>
        <li class="nav-item">
          <a class="sk-nav-link nav-link nav-more-item-mobile-items" href="../getting_started.html">Getting Started</a>
        </li>
        <li class="nav-item">
          <a class="sk-nav-link nav-link nav-more-item-mobile-items" href="../tutorial/index.html">Tutorial</a>
        </li>
        <li class="nav-item">
          <a class="sk-nav-link nav-link nav-more-item-mobile-items" href="../glossary.html">Glossary</a>
        </li>
        <li class="nav-item">
          <a class="sk-nav-link nav-link nav-more-item-mobile-items" href="index.html">Development</a>
        </li>
        <li class="nav-item">
          <a class="sk-nav-link nav-link nav-more-item-mobile-items" href="../faq.html">FAQ</a>
        </li>
        <li class="nav-item">
          <a class="sk-nav-link nav-link nav-more-item-mobile-items" href="../related_projects.html">Related packages</a>
        </li>
        <li class="nav-item">
          <a class="sk-nav-link nav-link nav-more-item-mobile-items" href="../roadmap.html">Roadmap</a>
        </li>
        <li class="nav-item">
          <a class="sk-nav-link nav-link nav-more-item-mobile-items" href="../about.html">About us</a>
        </li>
        <li class="nav-item">
          <a class="sk-nav-link nav-link nav-more-item-mobile-items" href="https://github.com/scikit-learn/scikit-learn">GitHub</a>
        </li>
        <li class="nav-item">
          <a class="sk-nav-link nav-link nav-more-item-mobile-items" href="https://scikit-learn.org/dev/versions.html">Other Versions</a>
        </li>
        <li class="nav-item dropdown nav-more-item-dropdown">
          <a class="sk-nav-link nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">More</a>
          <div class="dropdown-menu" aria-labelledby="navbarDropdown">
              <a class="sk-nav-dropdown-item dropdown-item" href="../getting_started.html">Getting Started</a>
              <a class="sk-nav-dropdown-item dropdown-item" href="../tutorial/index.html">Tutorial</a>
              <a class="sk-nav-dropdown-item dropdown-item" href="../glossary.html">Glossary</a>
              <a class="sk-nav-dropdown-item dropdown-item" href="index.html">Development</a>
              <a class="sk-nav-dropdown-item dropdown-item" href="../faq.html">FAQ</a>
              <a class="sk-nav-dropdown-item dropdown-item" href="../related_projects.html">Related packages</a>
              <a class="sk-nav-dropdown-item dropdown-item" href="../roadmap.html">Roadmap</a>
              <a class="sk-nav-dropdown-item dropdown-item" href="../about.html">About us</a>
              <a class="sk-nav-dropdown-item dropdown-item" href="https://github.com/scikit-learn/scikit-learn">GitHub</a>
              <a class="sk-nav-dropdown-item dropdown-item" href="https://scikit-learn.org/dev/versions.html">Other Versions</a>
          </div>
        </li>
      </ul>
      <div id="searchbox" role="search">
          <div class="searchformwrapper">
          <form class="search" action="../search.html" method="get">
            <input class="sk-search-text-input" type="text" name="q" aria-labelledby="searchlabel" />
            <input class="sk-search-text-btn" type="submit" value="Go" />
          </form>
          </div>
      </div>
    </div>
  </div>
</nav>
<div class="d-flex" id="sk-doc-wrapper">
    <input type="checkbox" name="sk-toggle-checkbox" id="sk-toggle-checkbox">
    <label id="sk-sidemenu-toggle" class="sk-btn-toggle-toc btn sk-btn-primary" for="sk-toggle-checkbox">Toggle Menu</label>
    <div id="sk-sidebar-wrapper" class="border-right">
      <div class="sk-sidebar-toc-wrapper">
        <div class="sk-sidebar-toc-logo">
          <a href="../index.html">
            <img
              class="sk-brand-img"
              src="../_static/scikit-learn-logo-small.png"
              alt="logo"/>
          </a>
        </div>
        <div class="btn-group w-100 mb-2" role="group" aria-label="rellinks">
            <a href="utilities.html" role="button" class="btn sk-btn-rellink py-1" sk-rellink-tooltip="Utilities for Developers">Prev</a><a href="index.html" role="button" class="btn sk-btn-rellink py-1" sk-rellink-tooltip="Developer’s Guide">Up</a>
            <a href="advanced_installation.html" role="button" class="btn sk-btn-rellink py-1" sk-rellink-tooltip="Installing the development version of scikit-learn">Next</a>
        </div>
        <div class="alert alert-danger p-1 mb-2" role="alert">
          <p class="text-center mb-0">
          <strong>scikit-learn 0.22</strong><br/>
          <a href="http://scikit-learn.org/dev/versions.html">Other versions</a>
          </p>
        </div>
        <div class="alert alert-warning p-1 mb-2" role="alert">
          <p class="text-center mb-0">
            Please <a class="font-weight-bold" href="../about.html#citing-scikit-learn"><string>cite us</string></a> if you use the software.
          </p>
        </div>
          <div class="sk-sidebar-toc">
            <ul>
<li><a class="reference internal" href="#">How to optimize for speed</a><ul>
<li><a class="reference internal" href="#python-cython-or-c-c">Python, Cython or C/C++?</a></li>
<li><a class="reference internal" href="#profiling-python-code">Profiling Python code</a></li>
<li><a class="reference internal" href="#memory-usage-profiling">Memory usage profiling</a></li>
<li><a class="reference internal" href="#performance-tips-for-the-cython-developer">Performance tips for the Cython developer</a><ul>
<li><a class="reference internal" href="#using-openmp">Using OpenMP</a></li>
</ul>
</li>
<li><a class="reference internal" href="#profiling-compiled-extensions">Profiling compiled extensions</a><ul>
<li><a class="reference internal" href="#using-yep-and-gperftools">Using yep and gperftools</a></li>
<li><a class="reference internal" href="#using-gprof">Using gprof</a></li>
<li><a class="reference internal" href="#using-valgrind-callgrind-kcachegrind">Using valgrind / callgrind / kcachegrind</a><ul>
<li><a class="reference internal" href="#kcachegrind">kcachegrind</a></li>
</ul>
</li>
</ul>
</li>
<li><a class="reference internal" href="#multi-core-parallelism-using-joblib-parallel">Multi-core parallelism using <code class="docutils literal notranslate"><span class="pre">joblib.Parallel</span></code></a></li>
<li><a class="reference internal" href="#a-simple-algorithmic-trick-warm-restarts">A simple algorithmic trick: warm restarts</a></li>
</ul>
</li>
</ul>

          </div>
      </div>
    </div>
    <div id="sk-page-content-wrapper">
      <div class="sk-page-content container-fluid body px-md-3" role="main">
        
  <div class="section" id="how-to-optimize-for-speed">
<span id="performance-howto"></span><h1>How to optimize for speed<a class="headerlink" href="#how-to-optimize-for-speed" title="Permalink to this headline">¶</a></h1>
<p>The following gives some practical guidelines to help you write efficient
code for the scikit-learn project.</p>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>While it is always useful to profile your code so as to <strong>check
performance assumptions</strong>, it is also highly recommended
to <strong>review the literature</strong> to ensure that the implemented algorithm
is the state of the art for the task before investing into costly
implementation optimization.</p>
<p>Times and times, hours of efforts invested in optimizing complicated
implementation details have been rendered irrelevant by the subsequent
discovery of simple <strong>algorithmic tricks</strong>, or by using another algorithm
altogether that is better suited to the problem.</p>
<p>The section <a class="reference internal" href="#warm-restarts"><span class="std std-ref">A simple algorithmic trick: warm restarts</span></a> gives an example of such a trick.</p>
</div>
<div class="section" id="python-cython-or-c-c">
<h2>Python, Cython or C/C++?<a class="headerlink" href="#python-cython-or-c-c" title="Permalink to this headline">¶</a></h2>
<p>In general, the scikit-learn project emphasizes the <strong>readability</strong> of
the source code to make it easy for the project users to dive into the
source code so as to understand how the algorithm behaves on their data
but also for ease of maintainability (by the developers).</p>
<p>When implementing a new algorithm is thus recommended to <strong>start
implementing it in Python using Numpy and Scipy</strong> by taking care of avoiding
looping code using the vectorized idioms of those libraries. In practice
this means trying to <strong>replace any nested for loops by calls to equivalent
Numpy array methods</strong>. The goal is to avoid the CPU wasting time in the
Python interpreter rather than crunching numbers to fit your statistical
model. It’s generally a good idea to consider NumPy and SciPy performance tips:
<a class="reference external" href="https://scipy.github.io/old-wiki/pages/PerformanceTips">https://scipy.github.io/old-wiki/pages/PerformanceTips</a></p>
<p>Sometimes however an algorithm cannot be expressed efficiently in simple
vectorized Numpy code. In this case, the recommended strategy is the
following:</p>
<blockquote>
<div><ol class="arabic simple">
<li><p><strong>Profile</strong> the Python implementation to find the main bottleneck and
isolate it in a <strong>dedicated module level function</strong>. This function
will be reimplemented as a compiled extension module.</p></li>
<li><p>If there exists a well maintained BSD or MIT <strong>C/C++</strong> implementation
of the same algorithm that is not too big, you can write a
<strong>Cython wrapper</strong> for it and include a copy of the source code
of the library in the scikit-learn source tree: this strategy is
used for the classes <a class="reference internal" href="../modules/generated/sklearn.svm.LinearSVC.html#sklearn.svm.LinearSVC" title="sklearn.svm.LinearSVC"><code class="xref py py-class docutils literal notranslate"><span class="pre">svm.LinearSVC</span></code></a>, <a class="reference internal" href="../modules/generated/sklearn.svm.SVC.html#sklearn.svm.SVC" title="sklearn.svm.SVC"><code class="xref py py-class docutils literal notranslate"><span class="pre">svm.SVC</span></code></a> and
<a class="reference internal" href="../modules/generated/sklearn.linear_model.LogisticRegression.html#sklearn.linear_model.LogisticRegression" title="sklearn.linear_model.LogisticRegression"><code class="xref py py-class docutils literal notranslate"><span class="pre">linear_model.LogisticRegression</span></code></a> (wrappers for liblinear
and libsvm).</p></li>
<li><p>Otherwise, write an optimized version of your Python function using
<strong>Cython</strong> directly. This strategy is used
for the <a class="reference internal" href="../modules/generated/sklearn.linear_model.ElasticNet.html#sklearn.linear_model.ElasticNet" title="sklearn.linear_model.ElasticNet"><code class="xref py py-class docutils literal notranslate"><span class="pre">linear_model.ElasticNet</span></code></a> and
<a class="reference internal" href="../modules/generated/sklearn.linear_model.SGDClassifier.html#sklearn.linear_model.SGDClassifier" title="sklearn.linear_model.SGDClassifier"><code class="xref py py-class docutils literal notranslate"><span class="pre">linear_model.SGDClassifier</span></code></a> classes for instance.</p></li>
<li><p><strong>Move the Python version of the function in the tests</strong> and use
it to check that the results of the compiled extension are consistent
with the gold standard, easy to debug Python version.</p></li>
<li><p>Once the code is optimized (not simple bottleneck spottable by
profiling), check whether it is possible to have <strong>coarse grained
parallelism</strong> that is amenable to <strong>multi-processing</strong> by using the
<code class="docutils literal notranslate"><span class="pre">joblib.Parallel</span></code> class.</p></li>
</ol>
</div></blockquote>
<p>When using Cython, use either</p>
<blockquote>
<div><p>$ python setup.py build_ext -i
$ python setup.py install</p>
</div></blockquote>
<p>to generate C files. You are responsible for adding .c/.cpp extensions along
with build parameters in each submodule <code class="docutils literal notranslate"><span class="pre">setup.py</span></code>.</p>
<p>C/C++ generated files are embedded in distributed stable packages. The goal is
to make it possible to install scikit-learn stable version
on any machine with Python, Numpy, Scipy and C/C++ compiler.</p>
</div>
<div class="section" id="profiling-python-code">
<span id="id1"></span><h2>Profiling Python code<a class="headerlink" href="#profiling-python-code" title="Permalink to this headline">¶</a></h2>
<p>In order to profile Python code we recommend to write a script that
loads and prepare you data and then use the IPython integrated profiler
for interactively exploring the relevant part for the code.</p>
<p>Suppose we want to profile the Non Negative Matrix Factorization module
of scikit-learn. Let us setup a new IPython session and load the digits
dataset and as in the <a class="reference internal" href="../auto_examples/classification/plot_digits_classification.html#sphx-glr-auto-examples-classification-plot-digits-classification-py"><span class="std std-ref">Recognizing hand-written digits</span></a> example:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">In</span> <span class="p">[</span><span class="mi">1</span><span class="p">]:</span> <span class="kn">from</span> <span class="nn">sklearn.decomposition</span> <span class="kn">import</span> <span class="n">NMF</span>

<span class="n">In</span> <span class="p">[</span><span class="mi">2</span><span class="p">]:</span> <span class="kn">from</span> <span class="nn">sklearn.datasets</span> <span class="kn">import</span> <span class="n">load_digits</span>

<span class="n">In</span> <span class="p">[</span><span class="mi">3</span><span class="p">]:</span> <span class="n">X</span><span class="p">,</span> <span class="n">_</span> <span class="o">=</span> <span class="n">load_digits</span><span class="p">(</span><span class="n">return_X_y</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
</pre></div>
</div>
<p>Before starting the profiling session and engaging in tentative
optimization iterations, it is important to measure the total execution
time of the function we want to optimize without any kind of profiler
overhead and save it somewhere for later reference:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">In</span> <span class="p">[</span><span class="mi">4</span><span class="p">]:</span> <span class="o">%</span><span class="n">timeit</span> <span class="n">NMF</span><span class="p">(</span><span class="n">n_components</span><span class="o">=</span><span class="mi">16</span><span class="p">,</span> <span class="n">tol</span><span class="o">=</span><span class="mf">1e-2</span><span class="p">)</span><span class="o">.</span><span class="n">fit</span><span class="p">(</span><span class="n">X</span><span class="p">)</span>
<span class="mi">1</span> <span class="n">loops</span><span class="p">,</span> <span class="n">best</span> <span class="n">of</span> <span class="mi">3</span><span class="p">:</span> <span class="mf">1.7</span> <span class="n">s</span> <span class="n">per</span> <span class="n">loop</span>
</pre></div>
</div>
<p>To have a look at the overall performance profile using the <code class="docutils literal notranslate"><span class="pre">%prun</span></code>
magic command:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">In</span> <span class="p">[</span><span class="mi">5</span><span class="p">]:</span> <span class="o">%</span><span class="n">prun</span> <span class="o">-</span><span class="n">l</span> <span class="n">nmf</span><span class="o">.</span><span class="n">py</span> <span class="n">NMF</span><span class="p">(</span><span class="n">n_components</span><span class="o">=</span><span class="mi">16</span><span class="p">,</span> <span class="n">tol</span><span class="o">=</span><span class="mf">1e-2</span><span class="p">)</span><span class="o">.</span><span class="n">fit</span><span class="p">(</span><span class="n">X</span><span class="p">)</span>
         <span class="mi">14496</span> <span class="n">function</span> <span class="n">calls</span> <span class="ow">in</span> <span class="mf">1.682</span> <span class="n">CPU</span> <span class="n">seconds</span>

   <span class="n">Ordered</span> <span class="n">by</span><span class="p">:</span> <span class="n">internal</span> <span class="n">time</span>
   <span class="n">List</span> <span class="n">reduced</span> <span class="kn">from</span> <span class="mi">90</span> <span class="n">to</span> <span class="mi">9</span> <span class="n">due</span> <span class="n">to</span> <span class="n">restriction</span> <span class="o">&lt;</span><span class="s1">&#39;nmf.py&#39;</span><span class="o">&gt;</span>

   <span class="n">ncalls</span>  <span class="n">tottime</span>  <span class="n">percall</span>  <span class="n">cumtime</span>  <span class="n">percall</span> <span class="n">filename</span><span class="p">:</span><span class="n">lineno</span><span class="p">(</span><span class="n">function</span><span class="p">)</span>
       <span class="mi">36</span>    <span class="mf">0.609</span>    <span class="mf">0.017</span>    <span class="mf">1.499</span>    <span class="mf">0.042</span> <span class="n">nmf</span><span class="o">.</span><span class="n">py</span><span class="p">:</span><span class="mi">151</span><span class="p">(</span><span class="n">_nls_subproblem</span><span class="p">)</span>
     <span class="mi">1263</span>    <span class="mf">0.157</span>    <span class="mf">0.000</span>    <span class="mf">0.157</span>    <span class="mf">0.000</span> <span class="n">nmf</span><span class="o">.</span><span class="n">py</span><span class="p">:</span><span class="mi">18</span><span class="p">(</span><span class="n">_pos</span><span class="p">)</span>
        <span class="mi">1</span>    <span class="mf">0.053</span>    <span class="mf">0.053</span>    <span class="mf">1.681</span>    <span class="mf">1.681</span> <span class="n">nmf</span><span class="o">.</span><span class="n">py</span><span class="p">:</span><span class="mi">352</span><span class="p">(</span><span class="n">fit_transform</span><span class="p">)</span>
      <span class="mi">673</span>    <span class="mf">0.008</span>    <span class="mf">0.000</span>    <span class="mf">0.057</span>    <span class="mf">0.000</span> <span class="n">nmf</span><span class="o">.</span><span class="n">py</span><span class="p">:</span><span class="mi">28</span><span class="p">(</span><span class="n">norm</span><span class="p">)</span>
        <span class="mi">1</span>    <span class="mf">0.006</span>    <span class="mf">0.006</span>    <span class="mf">0.047</span>    <span class="mf">0.047</span> <span class="n">nmf</span><span class="o">.</span><span class="n">py</span><span class="p">:</span><span class="mi">42</span><span class="p">(</span><span class="n">_initialize_nmf</span><span class="p">)</span>
       <span class="mi">36</span>    <span class="mf">0.001</span>    <span class="mf">0.000</span>    <span class="mf">0.010</span>    <span class="mf">0.000</span> <span class="n">nmf</span><span class="o">.</span><span class="n">py</span><span class="p">:</span><span class="mi">36</span><span class="p">(</span><span class="n">_sparseness</span><span class="p">)</span>
       <span class="mi">30</span>    <span class="mf">0.001</span>    <span class="mf">0.000</span>    <span class="mf">0.001</span>    <span class="mf">0.000</span> <span class="n">nmf</span><span class="o">.</span><span class="n">py</span><span class="p">:</span><span class="mi">23</span><span class="p">(</span><span class="n">_neg</span><span class="p">)</span>
        <span class="mi">1</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span> <span class="n">nmf</span><span class="o">.</span><span class="n">py</span><span class="p">:</span><span class="mi">337</span><span class="p">(</span><span class="fm">__init__</span><span class="p">)</span>
        <span class="mi">1</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">1.681</span>    <span class="mf">1.681</span> <span class="n">nmf</span><span class="o">.</span><span class="n">py</span><span class="p">:</span><span class="mi">461</span><span class="p">(</span><span class="n">fit</span><span class="p">)</span>
</pre></div>
</div>
<p>The <code class="docutils literal notranslate"><span class="pre">tottime</span></code> column is the most interesting: it gives to total time spent
executing the code of a given function ignoring the time spent in executing the
sub-functions. The real total time (local code + sub-function calls) is given by
the <code class="docutils literal notranslate"><span class="pre">cumtime</span></code> column.</p>
<p>Note the use of the <code class="docutils literal notranslate"><span class="pre">-l</span> <span class="pre">nmf.py</span></code> that restricts the output to lines that
contains the “nmf.py” string. This is useful to have a quick look at the hotspot
of the nmf Python module it-self ignoring anything else.</p>
<p>Here is the beginning of the output of the same command without the <code class="docutils literal notranslate"><span class="pre">-l</span> <span class="pre">nmf.py</span></code>
filter:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">In</span> <span class="p">[</span><span class="mi">5</span><span class="p">]</span> <span class="o">%</span><span class="n">prun</span> <span class="n">NMF</span><span class="p">(</span><span class="n">n_components</span><span class="o">=</span><span class="mi">16</span><span class="p">,</span> <span class="n">tol</span><span class="o">=</span><span class="mf">1e-2</span><span class="p">)</span><span class="o">.</span><span class="n">fit</span><span class="p">(</span><span class="n">X</span><span class="p">)</span>
         <span class="mi">16159</span> <span class="n">function</span> <span class="n">calls</span> <span class="ow">in</span> <span class="mf">1.840</span> <span class="n">CPU</span> <span class="n">seconds</span>

   <span class="n">Ordered</span> <span class="n">by</span><span class="p">:</span> <span class="n">internal</span> <span class="n">time</span>

   <span class="n">ncalls</span>  <span class="n">tottime</span>  <span class="n">percall</span>  <span class="n">cumtime</span>  <span class="n">percall</span> <span class="n">filename</span><span class="p">:</span><span class="n">lineno</span><span class="p">(</span><span class="n">function</span><span class="p">)</span>
     <span class="mi">2833</span>    <span class="mf">0.653</span>    <span class="mf">0.000</span>    <span class="mf">0.653</span>    <span class="mf">0.000</span> <span class="p">{</span><span class="n">numpy</span><span class="o">.</span><span class="n">core</span><span class="o">.</span><span class="n">_dotblas</span><span class="o">.</span><span class="n">dot</span><span class="p">}</span>
       <span class="mi">46</span>    <span class="mf">0.651</span>    <span class="mf">0.014</span>    <span class="mf">1.636</span>    <span class="mf">0.036</span> <span class="n">nmf</span><span class="o">.</span><span class="n">py</span><span class="p">:</span><span class="mi">151</span><span class="p">(</span><span class="n">_nls_subproblem</span><span class="p">)</span>
     <span class="mi">1397</span>    <span class="mf">0.171</span>    <span class="mf">0.000</span>    <span class="mf">0.171</span>    <span class="mf">0.000</span> <span class="n">nmf</span><span class="o">.</span><span class="n">py</span><span class="p">:</span><span class="mi">18</span><span class="p">(</span><span class="n">_pos</span><span class="p">)</span>
     <span class="mi">2780</span>    <span class="mf">0.167</span>    <span class="mf">0.000</span>    <span class="mf">0.167</span>    <span class="mf">0.000</span> <span class="p">{</span><span class="n">method</span> <span class="s1">&#39;sum&#39;</span> <span class="n">of</span> <span class="s1">&#39;numpy.ndarray&#39;</span> <span class="n">objects</span><span class="p">}</span>
        <span class="mi">1</span>    <span class="mf">0.064</span>    <span class="mf">0.064</span>    <span class="mf">1.840</span>    <span class="mf">1.840</span> <span class="n">nmf</span><span class="o">.</span><span class="n">py</span><span class="p">:</span><span class="mi">352</span><span class="p">(</span><span class="n">fit_transform</span><span class="p">)</span>
     <span class="mi">1542</span>    <span class="mf">0.043</span>    <span class="mf">0.000</span>    <span class="mf">0.043</span>    <span class="mf">0.000</span> <span class="p">{</span><span class="n">method</span> <span class="s1">&#39;flatten&#39;</span> <span class="n">of</span> <span class="s1">&#39;numpy.ndarray&#39;</span> <span class="n">objects</span><span class="p">}</span>
      <span class="mi">337</span>    <span class="mf">0.019</span>    <span class="mf">0.000</span>    <span class="mf">0.019</span>    <span class="mf">0.000</span> <span class="p">{</span><span class="n">method</span> <span class="s1">&#39;all&#39;</span> <span class="n">of</span> <span class="s1">&#39;numpy.ndarray&#39;</span> <span class="n">objects</span><span class="p">}</span>
     <span class="mi">2734</span>    <span class="mf">0.011</span>    <span class="mf">0.000</span>    <span class="mf">0.181</span>    <span class="mf">0.000</span> <span class="n">fromnumeric</span><span class="o">.</span><span class="n">py</span><span class="p">:</span><span class="mi">1185</span><span class="p">(</span><span class="nb">sum</span><span class="p">)</span>
        <span class="mi">2</span>    <span class="mf">0.010</span>    <span class="mf">0.005</span>    <span class="mf">0.010</span>    <span class="mf">0.005</span> <span class="p">{</span><span class="n">numpy</span><span class="o">.</span><span class="n">linalg</span><span class="o">.</span><span class="n">lapack_lite</span><span class="o">.</span><span class="n">dgesdd</span><span class="p">}</span>
      <span class="mi">748</span>    <span class="mf">0.009</span>    <span class="mf">0.000</span>    <span class="mf">0.065</span>    <span class="mf">0.000</span> <span class="n">nmf</span><span class="o">.</span><span class="n">py</span><span class="p">:</span><span class="mi">28</span><span class="p">(</span><span class="n">norm</span><span class="p">)</span>
<span class="o">...</span>
</pre></div>
</div>
<p>The above results show that the execution is largely dominated by
dot products operations (delegated to blas). Hence there is probably
no huge gain to expect by rewriting this code in Cython or C/C++: in
this case out of the 1.7s total execution time, almost 0.7s are spent
in compiled code we can consider optimal. By rewriting the rest of the
Python code and assuming we could achieve a 1000% boost on this portion
(which is highly unlikely given the shallowness of the Python loops),
we would not gain more than a 2.4x speed-up globally.</p>
<p>Hence major improvements can only be achieved by <strong>algorithmic
improvements</strong> in this particular example (e.g. trying to find operation
that are both costly and useless to avoid computing then rather than
trying to optimize their implementation).</p>
<p>It is however still interesting to check what’s happening inside the
<code class="docutils literal notranslate"><span class="pre">_nls_subproblem</span></code> function which is the hotspot if we only consider
Python code: it takes around 100% of the accumulated time of the module. In
order to better understand the profile of this specific function, let
us install <code class="docutils literal notranslate"><span class="pre">line_profiler</span></code> and wire it to IPython:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>$ pip install line_profiler
</pre></div>
</div>
<ul>
<li><p><strong>Under IPython 0.13+</strong>, first create a configuration profile:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>$ ipython profile create
</pre></div>
</div>
<p>Then register the line_profiler extension in
<code class="docutils literal notranslate"><span class="pre">~/.ipython/profile_default/ipython_config.py</span></code>:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">c</span><span class="o">.</span><span class="n">TerminalIPythonApp</span><span class="o">.</span><span class="n">extensions</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s1">&#39;line_profiler&#39;</span><span class="p">)</span>
<span class="n">c</span><span class="o">.</span><span class="n">InteractiveShellApp</span><span class="o">.</span><span class="n">extensions</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s1">&#39;line_profiler&#39;</span><span class="p">)</span>
</pre></div>
</div>
<p>This will register the <code class="docutils literal notranslate"><span class="pre">%lprun</span></code> magic command in the IPython terminal
application and the other frontends such as qtconsole and notebook.</p>
</li>
</ul>
<p>Now restart IPython and let us use this new toy:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">In</span> <span class="p">[</span><span class="mi">1</span><span class="p">]:</span> <span class="kn">from</span> <span class="nn">sklearn.datasets</span> <span class="kn">import</span> <span class="n">load_digits</span>

<span class="n">In</span> <span class="p">[</span><span class="mi">2</span><span class="p">]:</span> <span class="kn">from</span> <span class="nn">sklearn.decomposition</span> <span class="kn">import</span> <span class="n">NMF</span>
  <span class="o">...</span> <span class="p">:</span> <span class="kn">from</span> <span class="nn">sklearn.decomposition._nmf</span> <span class="kn">import</span> <span class="n">_nls_subproblem</span>

<span class="n">In</span> <span class="p">[</span><span class="mi">3</span><span class="p">]:</span> <span class="n">X</span><span class="p">,</span> <span class="n">_</span> <span class="o">=</span> <span class="n">load_digits</span><span class="p">(</span><span class="n">return_X_y</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>

<span class="n">In</span> <span class="p">[</span><span class="mi">4</span><span class="p">]:</span> <span class="o">%</span><span class="n">lprun</span> <span class="o">-</span><span class="n">f</span> <span class="n">_nls_subproblem</span> <span class="n">NMF</span><span class="p">(</span><span class="n">n_components</span><span class="o">=</span><span class="mi">16</span><span class="p">,</span> <span class="n">tol</span><span class="o">=</span><span class="mf">1e-2</span><span class="p">)</span><span class="o">.</span><span class="n">fit</span><span class="p">(</span><span class="n">X</span><span class="p">)</span>
<span class="n">Timer</span> <span class="n">unit</span><span class="p">:</span> <span class="mf">1e-06</span> <span class="n">s</span>

<span class="n">File</span><span class="p">:</span> <span class="n">sklearn</span><span class="o">/</span><span class="n">decomposition</span><span class="o">/</span><span class="n">nmf</span><span class="o">.</span><span class="n">py</span>
<span class="n">Function</span><span class="p">:</span> <span class="n">_nls_subproblem</span> <span class="n">at</span> <span class="n">line</span> <span class="mi">137</span>
<span class="n">Total</span> <span class="n">time</span><span class="p">:</span> <span class="mf">1.73153</span> <span class="n">s</span>

<span class="n">Line</span> <span class="c1">#      Hits         Time  Per Hit   % Time  Line Contents</span>
<span class="o">==============================================================</span>
   <span class="mi">137</span>                                           <span class="k">def</span> <span class="nf">_nls_subproblem</span><span class="p">(</span><span class="n">V</span><span class="p">,</span> <span class="n">W</span><span class="p">,</span> <span class="n">H_init</span><span class="p">,</span> <span class="n">tol</span><span class="p">,</span> <span class="n">max_iter</span><span class="p">):</span>
   <span class="mi">138</span>                                               <span class="s2">&quot;&quot;&quot;Non-negative least square solver</span>
<span class="s2">   ...</span>
<span class="s2">   170                                               &quot;&quot;&quot;</span>
   <span class="mi">171</span>        <span class="mi">48</span>         <span class="mi">5863</span>    <span class="mf">122.1</span>      <span class="mf">0.3</span>      <span class="k">if</span> <span class="p">(</span><span class="n">H_init</span> <span class="o">&lt;</span> <span class="mi">0</span><span class="p">)</span><span class="o">.</span><span class="n">any</span><span class="p">():</span>
   <span class="mi">172</span>                                                   <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s2">&quot;Negative values in H_init passed to NLS solver.&quot;</span><span class="p">)</span>
   <span class="mi">173</span>
   <span class="mi">174</span>        <span class="mi">48</span>          <span class="mi">139</span>      <span class="mf">2.9</span>      <span class="mf">0.0</span>      <span class="n">H</span> <span class="o">=</span> <span class="n">H_init</span>
   <span class="mi">175</span>        <span class="mi">48</span>       <span class="mi">112141</span>   <span class="mf">2336.3</span>      <span class="mf">5.8</span>      <span class="n">WtV</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">dot</span><span class="p">(</span><span class="n">W</span><span class="o">.</span><span class="n">T</span><span class="p">,</span> <span class="n">V</span><span class="p">)</span>
   <span class="mi">176</span>        <span class="mi">48</span>        <span class="mi">16144</span>    <span class="mf">336.3</span>      <span class="mf">0.8</span>      <span class="n">WtW</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">dot</span><span class="p">(</span><span class="n">W</span><span class="o">.</span><span class="n">T</span><span class="p">,</span> <span class="n">W</span><span class="p">)</span>
   <span class="mi">177</span>
   <span class="mi">178</span>                                               <span class="c1"># values justified in the paper</span>
   <span class="mi">179</span>        <span class="mi">48</span>          <span class="mi">144</span>      <span class="mf">3.0</span>      <span class="mf">0.0</span>      <span class="n">alpha</span> <span class="o">=</span> <span class="mi">1</span>
   <span class="mi">180</span>        <span class="mi">48</span>          <span class="mi">113</span>      <span class="mf">2.4</span>      <span class="mf">0.0</span>      <span class="n">beta</span> <span class="o">=</span> <span class="mf">0.1</span>
   <span class="mi">181</span>       <span class="mi">638</span>         <span class="mi">1880</span>      <span class="mf">2.9</span>      <span class="mf">0.1</span>      <span class="k">for</span> <span class="n">n_iter</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">max_iter</span> <span class="o">+</span> <span class="mi">1</span><span class="p">):</span>
   <span class="mi">182</span>       <span class="mi">638</span>       <span class="mi">195133</span>    <span class="mf">305.9</span>     <span class="mf">10.2</span>          <span class="n">grad</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">dot</span><span class="p">(</span><span class="n">WtW</span><span class="p">,</span> <span class="n">H</span><span class="p">)</span> <span class="o">-</span> <span class="n">WtV</span>
   <span class="mi">183</span>       <span class="mi">638</span>       <span class="mi">495761</span>    <span class="mf">777.1</span>     <span class="mf">25.9</span>          <span class="n">proj_gradient</span> <span class="o">=</span> <span class="n">norm</span><span class="p">(</span><span class="n">grad</span><span class="p">[</span><span class="n">np</span><span class="o">.</span><span class="n">logical_or</span><span class="p">(</span><span class="n">grad</span> <span class="o">&lt;</span> <span class="mi">0</span><span class="p">,</span> <span class="n">H</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">)])</span>
   <span class="mi">184</span>       <span class="mi">638</span>         <span class="mi">2449</span>      <span class="mf">3.8</span>      <span class="mf">0.1</span>          <span class="k">if</span> <span class="n">proj_gradient</span> <span class="o">&lt;</span> <span class="n">tol</span><span class="p">:</span>
   <span class="mi">185</span>        <span class="mi">48</span>          <span class="mi">130</span>      <span class="mf">2.7</span>      <span class="mf">0.0</span>              <span class="k">break</span>
   <span class="mi">186</span>
   <span class="mi">187</span>      <span class="mi">1474</span>         <span class="mi">4474</span>      <span class="mf">3.0</span>      <span class="mf">0.2</span>          <span class="k">for</span> <span class="n">inner_iter</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">20</span><span class="p">):</span>
   <span class="mi">188</span>      <span class="mi">1474</span>        <span class="mi">83833</span>     <span class="mf">56.9</span>      <span class="mf">4.4</span>              <span class="n">Hn</span> <span class="o">=</span> <span class="n">H</span> <span class="o">-</span> <span class="n">alpha</span> <span class="o">*</span> <span class="n">grad</span>
   <span class="mi">189</span>                                                       <span class="c1"># Hn = np.where(Hn &gt; 0, Hn, 0)</span>
   <span class="mi">190</span>      <span class="mi">1474</span>       <span class="mi">194239</span>    <span class="mf">131.8</span>     <span class="mf">10.1</span>              <span class="n">Hn</span> <span class="o">=</span> <span class="n">_pos</span><span class="p">(</span><span class="n">Hn</span><span class="p">)</span>
   <span class="mi">191</span>      <span class="mi">1474</span>        <span class="mi">48858</span>     <span class="mf">33.1</span>      <span class="mf">2.5</span>              <span class="n">d</span> <span class="o">=</span> <span class="n">Hn</span> <span class="o">-</span> <span class="n">H</span>
   <span class="mi">192</span>      <span class="mi">1474</span>       <span class="mi">150407</span>    <span class="mf">102.0</span>      <span class="mf">7.8</span>              <span class="n">gradd</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">sum</span><span class="p">(</span><span class="n">grad</span> <span class="o">*</span> <span class="n">d</span><span class="p">)</span>
   <span class="mi">193</span>      <span class="mi">1474</span>       <span class="mi">515390</span>    <span class="mf">349.7</span>     <span class="mf">26.9</span>              <span class="n">dQd</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">sum</span><span class="p">(</span><span class="n">np</span><span class="o">.</span><span class="n">dot</span><span class="p">(</span><span class="n">WtW</span><span class="p">,</span> <span class="n">d</span><span class="p">)</span> <span class="o">*</span> <span class="n">d</span><span class="p">)</span>
   <span class="o">...</span>
</pre></div>
</div>
<p>By looking at the top values of the <code class="docutils literal notranslate"><span class="pre">%</span> <span class="pre">Time</span></code> column it is really easy to
pin-point the most expensive expressions that would deserve additional care.</p>
</div>
<div class="section" id="memory-usage-profiling">
<h2>Memory usage profiling<a class="headerlink" href="#memory-usage-profiling" title="Permalink to this headline">¶</a></h2>
<p>You can analyze in detail the memory usage of any Python code with the help of
<a class="reference external" href="https://pypi.org/project/memory_profiler/">memory_profiler</a>. First,
install the latest version:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>$ pip install -U memory_profiler
</pre></div>
</div>
<p>Then, setup the magics in a manner similar to <code class="docutils literal notranslate"><span class="pre">line_profiler</span></code>.</p>
<ul>
<li><p><strong>Under IPython 0.11+</strong>, first create a configuration profile:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>$ ipython profile create
</pre></div>
</div>
<p>Then register the extension in
<code class="docutils literal notranslate"><span class="pre">~/.ipython/profile_default/ipython_config.py</span></code>
alongside the line profiler:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">c</span><span class="o">.</span><span class="n">TerminalIPythonApp</span><span class="o">.</span><span class="n">extensions</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s1">&#39;memory_profiler&#39;</span><span class="p">)</span>
<span class="n">c</span><span class="o">.</span><span class="n">InteractiveShellApp</span><span class="o">.</span><span class="n">extensions</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s1">&#39;memory_profiler&#39;</span><span class="p">)</span>
</pre></div>
</div>
<p>This will register the <code class="docutils literal notranslate"><span class="pre">%memit</span></code> and <code class="docutils literal notranslate"><span class="pre">%mprun</span></code> magic commands in the
IPython terminal application and the other frontends such as qtconsole and
notebook.</p>
</li>
</ul>
<p><code class="docutils literal notranslate"><span class="pre">%mprun</span></code> is useful to examine, line-by-line, the memory usage of key
functions in your program. It is very similar to <code class="docutils literal notranslate"><span class="pre">%lprun</span></code>, discussed in the
previous section. For example, from the <code class="docutils literal notranslate"><span class="pre">memory_profiler</span></code> <code class="docutils literal notranslate"><span class="pre">examples</span></code>
directory:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">In</span> <span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="kn">from</span> <span class="nn">example</span> <span class="kn">import</span> <span class="n">my_func</span>

<span class="n">In</span> <span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">%</span><span class="n">mprun</span> <span class="o">-</span><span class="n">f</span> <span class="n">my_func</span> <span class="n">my_func</span><span class="p">()</span>
<span class="n">Filename</span><span class="p">:</span> <span class="n">example</span><span class="o">.</span><span class="n">py</span>

<span class="n">Line</span> <span class="c1">#    Mem usage  Increment   Line Contents</span>
<span class="o">==============================================</span>
     <span class="mi">3</span>                           <span class="nd">@profile</span>
     <span class="mi">4</span>      <span class="mf">5.97</span> <span class="n">MB</span>    <span class="mf">0.00</span> <span class="n">MB</span>   <span class="k">def</span> <span class="nf">my_func</span><span class="p">():</span>
     <span class="mi">5</span>     <span class="mf">13.61</span> <span class="n">MB</span>    <span class="mf">7.64</span> <span class="n">MB</span>       <span class="n">a</span> <span class="o">=</span> <span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">*</span> <span class="p">(</span><span class="mi">10</span> <span class="o">**</span> <span class="mi">6</span><span class="p">)</span>
     <span class="mi">6</span>    <span class="mf">166.20</span> <span class="n">MB</span>  <span class="mf">152.59</span> <span class="n">MB</span>       <span class="n">b</span> <span class="o">=</span> <span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">*</span> <span class="p">(</span><span class="mi">2</span> <span class="o">*</span> <span class="mi">10</span> <span class="o">**</span> <span class="mi">7</span><span class="p">)</span>
     <span class="mi">7</span>     <span class="mf">13.61</span> <span class="n">MB</span> <span class="o">-</span><span class="mf">152.59</span> <span class="n">MB</span>       <span class="k">del</span> <span class="n">b</span>
     <span class="mi">8</span>     <span class="mf">13.61</span> <span class="n">MB</span>    <span class="mf">0.00</span> <span class="n">MB</span>       <span class="k">return</span> <span class="n">a</span>
</pre></div>
</div>
<p>Another useful magic that <code class="docutils literal notranslate"><span class="pre">memory_profiler</span></code> defines is <code class="docutils literal notranslate"><span class="pre">%memit</span></code>, which is
analogous to <code class="docutils literal notranslate"><span class="pre">%timeit</span></code>. It can be used as follows:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">In</span> <span class="p">[</span><span class="mi">1</span><span class="p">]:</span> <span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="nn">np</span>

<span class="n">In</span> <span class="p">[</span><span class="mi">2</span><span class="p">]:</span> <span class="o">%</span><span class="n">memit</span> <span class="n">np</span><span class="o">.</span><span class="n">zeros</span><span class="p">(</span><span class="mf">1e7</span><span class="p">)</span>
<span class="n">maximum</span> <span class="n">of</span> <span class="mi">3</span><span class="p">:</span> <span class="mf">76.402344</span> <span class="n">MB</span> <span class="n">per</span> <span class="n">loop</span>
</pre></div>
</div>
<p>For more details, see the docstrings of the magics, using <code class="docutils literal notranslate"><span class="pre">%memit?</span></code> and
<code class="docutils literal notranslate"><span class="pre">%mprun?</span></code>.</p>
</div>
<div class="section" id="performance-tips-for-the-cython-developer">
<h2>Performance tips for the Cython developer<a class="headerlink" href="#performance-tips-for-the-cython-developer" title="Permalink to this headline">¶</a></h2>
<p>If profiling of the Python code reveals that the Python interpreter
overhead is larger by one order of magnitude or more than the cost of the
actual numerical computation (e.g. <code class="docutils literal notranslate"><span class="pre">for</span></code> loops over vector components,
nested evaluation of conditional expression, scalar arithmetic…), it
is probably adequate to extract the hotspot portion of the code as a
standalone function in a <code class="docutils literal notranslate"><span class="pre">.pyx</span></code> file, add static type declarations and
then use Cython to generate a C program suitable to be compiled as a
Python extension module.</p>
<p>The official documentation available at <a class="reference external" href="http://docs.cython.org/">http://docs.cython.org/</a> contains
a tutorial and reference guide for developing such a module. In the
following we will just highlight a couple of tricks that we found
important in practice on the existing cython codebase in the scikit-learn
project.</p>
<p>TODO: html report, type declarations, bound checks, division by zero checks,
memory alignment, direct blas calls…</p>
<ul class="simple">
<li><p><a class="reference external" href="https://www.youtube.com/watch?v=gMvkiQ-gOW8">https://www.youtube.com/watch?v=gMvkiQ-gOW8</a></p></li>
<li><p><a class="reference external" href="http://conference.scipy.org/proceedings/SciPy2009/paper_1/">http://conference.scipy.org/proceedings/SciPy2009/paper_1/</a></p></li>
<li><p><a class="reference external" href="http://conference.scipy.org/proceedings/SciPy2009/paper_2/">http://conference.scipy.org/proceedings/SciPy2009/paper_2/</a></p></li>
</ul>
<div class="section" id="using-openmp">
<h3>Using OpenMP<a class="headerlink" href="#using-openmp" title="Permalink to this headline">¶</a></h3>
<p>Since scikit-learn can be built without OpenMP, it’s necessary to
protect each direct call to OpenMP. This can be done using the following
syntax:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1"># importing OpenMP</span>
<span class="n">IF</span> <span class="n">SKLEARN_OPENMP_PARALLELISM_ENABLED</span><span class="p">:</span>
    <span class="n">cimport</span> <span class="n">openmp</span>

<span class="c1"># calling OpenMP</span>
<span class="n">IF</span> <span class="n">SKLEARN_OPENMP_PARALLELISM_ENABLED</span><span class="p">:</span>
    <span class="n">max_threads</span> <span class="o">=</span> <span class="n">openmp</span><span class="o">.</span><span class="n">omp_get_max_threads</span><span class="p">()</span>
<span class="n">ELSE</span><span class="p">:</span>
    <span class="n">max_threads</span> <span class="o">=</span> <span class="mi">1</span>
</pre></div>
</div>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Protecting the parallel loop, <code class="docutils literal notranslate"><span class="pre">prange</span></code>, is already done by cython.</p>
</div>
</div>
</div>
<div class="section" id="profiling-compiled-extensions">
<span id="profiling-compiled-extension"></span><h2>Profiling compiled extensions<a class="headerlink" href="#profiling-compiled-extensions" title="Permalink to this headline">¶</a></h2>
<p>When working with compiled extensions (written in C/C++ with a wrapper or
directly as Cython extension), the default Python profiler is useless:
we need a dedicated tool to introspect what’s happening inside the
compiled extension it-self.</p>
<div class="section" id="using-yep-and-gperftools">
<h3>Using yep and gperftools<a class="headerlink" href="#using-yep-and-gperftools" title="Permalink to this headline">¶</a></h3>
<p>Easy profiling without special compilation options use yep:</p>
<ul class="simple">
<li><p><a class="reference external" href="https://pypi.org/project/yep/">https://pypi.org/project/yep/</a></p></li>
<li><p><a class="reference external" href="http://fa.bianp.net/blog/2011/a-profiler-for-python-extensions">http://fa.bianp.net/blog/2011/a-profiler-for-python-extensions</a></p></li>
</ul>
</div>
<div class="section" id="using-gprof">
<h3>Using gprof<a class="headerlink" href="#using-gprof" title="Permalink to this headline">¶</a></h3>
<p>In order to profile compiled Python extensions one could use <code class="docutils literal notranslate"><span class="pre">gprof</span></code>
after having recompiled the project with <code class="docutils literal notranslate"><span class="pre">gcc</span> <span class="pre">-pg</span></code> and using the
<code class="docutils literal notranslate"><span class="pre">python-dbg</span></code> variant of the interpreter on debian / ubuntu: however
this approach requires to also have <code class="docutils literal notranslate"><span class="pre">numpy</span></code> and <code class="docutils literal notranslate"><span class="pre">scipy</span></code> recompiled
with <code class="docutils literal notranslate"><span class="pre">-pg</span></code> which is rather complicated to get working.</p>
<p>Fortunately there exist two alternative profilers that don’t require you to
recompile everything.</p>
</div>
<div class="section" id="using-valgrind-callgrind-kcachegrind">
<h3>Using valgrind / callgrind / kcachegrind<a class="headerlink" href="#using-valgrind-callgrind-kcachegrind" title="Permalink to this headline">¶</a></h3>
<div class="section" id="kcachegrind">
<h4>kcachegrind<a class="headerlink" href="#kcachegrind" title="Permalink to this headline">¶</a></h4>
<p><code class="docutils literal notranslate"><span class="pre">yep</span></code> can be used to create a profiling report.
<code class="docutils literal notranslate"><span class="pre">kcachegrind</span></code> provides a graphical environment to visualize this report:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1"># Run yep to profile some python script</span>
<span class="n">python</span> <span class="o">-</span><span class="n">m</span> <span class="n">yep</span> <span class="o">-</span><span class="n">c</span> <span class="n">my_file</span><span class="o">.</span><span class="n">py</span>

<span class="c1"># open my_file.py.callgrin with kcachegrind</span>
<span class="n">kcachegrind</span> <span class="n">my_file</span><span class="o">.</span><span class="n">py</span><span class="o">.</span><span class="n">prof</span>
</pre></div>
</div>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p><code class="docutils literal notranslate"><span class="pre">yep</span></code> can be executed with the argument <code class="docutils literal notranslate"><span class="pre">--lines</span></code> or <code class="docutils literal notranslate"><span class="pre">-l</span></code> to compile
a profiling report ‘line by line’.</p>
</div>
</div>
</div>
</div>
<div class="section" id="multi-core-parallelism-using-joblib-parallel">
<h2>Multi-core parallelism using <code class="docutils literal notranslate"><span class="pre">joblib.Parallel</span></code><a class="headerlink" href="#multi-core-parallelism-using-joblib-parallel" title="Permalink to this headline">¶</a></h2>
<p>See <a class="reference external" href="https://joblib.readthedocs.io">joblib documentation</a></p>
</div>
<div class="section" id="a-simple-algorithmic-trick-warm-restarts">
<span id="warm-restarts"></span><h2>A simple algorithmic trick: warm restarts<a class="headerlink" href="#a-simple-algorithmic-trick-warm-restarts" title="Permalink to this headline">¶</a></h2>
<p>See the glossary entry for <a class="reference external" href="http://scikit-learn.org/dev/glossary.html#term-warm-start">warm_start</a></p>
</div>
</div>


      </div>
    <div class="container">
      <footer class="sk-content-footer">
            &copy; 2007 - 2019, scikit-learn developers (BSD License).
          <a href="../_sources/developers/performance.rst.txt" rel="nofollow">Show this page source</a>
      </footer>
    </div>
  </div>
</div>
<script src="../_static/js/vendor/bootstrap.min.js"></script>

<script>
    window.ga=window.ga||function(){(ga.q=ga.q||[]).push(arguments)};ga.l=+new Date;
    ga('create', 'UA-22606712-2', 'auto');
    ga('set', 'anonymizeIp', true);
    ga('send', 'pageview');
</script>
<script async src='https://www.google-analytics.com/analytics.js'></script>


<script>
$(document).ready(function() {
    /* Add a [>>>] button on the top-right corner of code samples to hide
     * the >>> and ... prompts and the output and thus make the code
     * copyable. */
    var div = $('.highlight-python .highlight,' +
                '.highlight-python3 .highlight,' +
                '.highlight-pycon .highlight,' +
		'.highlight-default .highlight')
    var pre = div.find('pre');

    // get the styles from the current theme
    pre.parent().parent().css('position', 'relative');
    var hide_text = 'Hide prompts and outputs';
    var show_text = 'Show prompts and outputs';

    // create and add the button to all the code blocks that contain >>>
    div.each(function(index) {
        var jthis = $(this);
        if (jthis.find('.gp').length > 0) {
            var button = $('<span class="copybutton">&gt;&gt;&gt;</span>');
            button.attr('title', hide_text);
            button.data('hidden', 'false');
            jthis.prepend(button);
        }
        // tracebacks (.gt) contain bare text elements that need to be
        // wrapped in a span to work with .nextUntil() (see later)
        jthis.find('pre:has(.gt)').contents().filter(function() {
            return ((this.nodeType == 3) && (this.data.trim().length > 0));
        }).wrap('<span>');
    });

    // define the behavior of the button when it's clicked
    $('.copybutton').click(function(e){
        e.preventDefault();
        var button = $(this);
        if (button.data('hidden') === 'false') {
            // hide the code output
            button.parent().find('.go, .gp, .gt').hide();
            button.next('pre').find('.gt').nextUntil('.gp, .go').css('visibility', 'hidden');
            button.css('text-decoration', 'line-through');
            button.attr('title', show_text);
            button.data('hidden', 'true');
        } else {
            // show the code output
            button.parent().find('.go, .gp, .gt').show();
            button.next('pre').find('.gt').nextUntil('.gp, .go').css('visibility', 'visible');
            button.css('text-decoration', 'none');
            button.attr('title', hide_text);
            button.data('hidden', 'false');
        }
    });

	/*** Add permalink buttons next to glossary terms ***/
	$('dl.glossary > dt[id]').append(function() {
		return ('<a class="headerlink" href="#' +
			    this.getAttribute('id') +
			    '" title="Permalink to this term">¶</a>');
	});
  /*** Hide navbar when scrolling down ***/
  // Returns true when headerlink target matches hash in url
  (function() {
    hashTargetOnTop = function() {
        var hash = window.location.hash;
        if ( hash.length < 2 ) { return false; }

        var target = document.getElementById( hash.slice(1) );
        if ( target === null ) { return false; }

        var top = target.getBoundingClientRect().top;
        return (top < 2) && (top > -2);
    };

    // Hide navbar on load if hash target is on top
    var navBar = document.getElementById("navbar");
    var navBarToggler = document.getElementById("sk-navbar-toggler");
    var navBarHeightHidden = "-" + navBar.getBoundingClientRect().height + "px";
    var $window = $(window);

    hideNavBar = function() {
        navBar.style.top = navBarHeightHidden;
    };

    showNavBar = function() {
        navBar.style.top = "0";
    }

    if (hashTargetOnTop()) {
        hideNavBar()
    }

    var prevScrollpos = window.pageYOffset;
    hideOnScroll = function(lastScrollTop) {
        if (($window.width() < 768) && (navBarToggler.getAttribute("aria-expanded") === 'true')) {
            return;
        }
        if (lastScrollTop > 2 && (prevScrollpos <= lastScrollTop) || hashTargetOnTop()){
            hideNavBar()
        } else {
            showNavBar()
        }
        prevScrollpos = lastScrollTop;
    };

    /*** high preformance scroll event listener***/
    var raf = window.requestAnimationFrame ||
        window.webkitRequestAnimationFrame ||
        window.mozRequestAnimationFrame ||
        window.msRequestAnimationFrame ||
        window.oRequestAnimationFrame;
    var lastScrollTop = $window.scrollTop();

    if (raf) {
        loop();
    }

    function loop() {
        var scrollTop = $window.scrollTop();
        if (lastScrollTop === scrollTop) {
            raf(loop);
            return;
        } else {
            lastScrollTop = scrollTop;
            hideOnScroll(lastScrollTop);
            raf(loop);
        }
    }
  })();
});

</script>
    
<script id="MathJax-script" async src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml.js"></script>
    
</body>
</html>